use std::fs::OpenOptions;
use std::io::Write;
use std::process::{Command, Stdio};
use std::thread::sleep;
use std::time::Duration;
use sysinfo::{ProcessExt, System, SystemExt};

pub async fn run_monitoring(args: Vec<String>) {
    if args.len() < 3 || args.contains(&String::from("--help")) {
        print_usage(&args[0]);
        return;
    }

    let process_name = &args[1];
    let script_path = &args[2];
    let timer_interval = parse_interval_arg(&args);
    let log_file = args.iter().find(|arg| arg.starts_with("--log="));
    monitor_process(process_name, script_path, timer_interval, log_file).await;
}

pub async fn monitor_process(
    process_name: &str,
    script_path: &str,
    timer_interval: Duration,
    log_file: Option<&String>,
) {
    let mut system = System::new_all();
    println!("已启动监控，间隔:{}(s)...", timer_interval.as_secs());
    if log_file.is_some() {
        println!("已开启成功日志");
    }
    loop {
        system.refresh_all();
        if !is_process_alive(&system, process_name) {
            start_process_with_script(script_path);
            sleep(Duration::from_secs(3));
            if let Some(log_filename) = log_file {
                let filename = log_filename.split('=').collect::<Vec<&str>>()[1];
                let system = System::new_all();
                if is_process_alive(&system, process_name) {
                    log(format!("启动成功,时间写入日志{}", filename));
                    if let Err(err) = append_to_log(filename) {
                        eprintln!("写日志失败: {}", err);
                    }
                } else {
                    println!("尝试启动，但未成功")
                }
            }
        }
        sleep(timer_interval);
        // println!("监控中...");
    }
}

fn parse_interval_arg(args: &[String]) -> Duration {
    let interval_arg = args.iter().find(|arg| arg.starts_with("--interval="));
    match interval_arg {
        Some(arg) => {
            let mut value = arg
                .trim_start_matches("--interval=")
                .parse::<u64>()
                .unwrap_or(5);
            value = std::cmp::max(value, 1);
            Duration::from_secs(value)
        }
        None => Duration::from_secs(5),
    }
}

fn print_usage(app_name: &str) {
    println!("Usage: ./{app_name} <process_name> <script_path> [--interval=5] [--log=watch.log]");
    println!("Options:");
    println!("  --interval=<seconds>  Sets the interval for monitoring in seconds (default: 5)");
    println!("  --log=<filename>      Specifies the log file to append timestamps");
    println!("  --help                Prints this help information");
}

pub fn append_to_log(log_filename: &str) -> std::io::Result<()> {
    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(log_filename)?;

    writeln!(
        file,
        "{}",
        Local::now().format("%Y-%m-%d %H:%M:%S").to_string()
    )?;

    Ok(())
}

fn is_process_alive(sys: &System, process_name: &str) -> bool {
    use std::env;
    let app_name = &env::args().next().unwrap();
    let app_name = app_name.to_string().split("/").last().unwrap().to_string();
    sys.processes().values().into_iter().any(|p| {
        let cmd = p.cmd().join(" ");
        // println!(
        //     "[DEBUG]procStatus={},contains={},app_name={} cmd = {}",
        //     p.status(),
        //     cmd.contains(process_name),
        //     app_name,
        //     cmd
        // );
        !cmd.contains(app_name.as_str()) && cmd.contains(process_name)
        // && p.status() == ProcessStatus::Run
    })
}

fn start_process_with_script(script_path: &str) {
    Command::new("sh")
        .arg(script_path)
        .stdin(Stdio::null()) // 禁用标准输入
        .stdout(Stdio::null()) // 禁用标准输出
        // .stderr(Stdio::null()) // 禁用标准错误输出
        .spawn()
        .ok();
    log(format!("运行脚本{}", script_path));
}

use chrono::prelude::*;
fn log(msg: String) {
    println!(
        "{} {}",
        Local::now().format("%Y-%m-%d %H:%M:%S").to_string(),
        msg
    );
}
